﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Cryptography;
using System.ComponentModel.DataAnnotations;
using System.Configuration;

namespace MobiShop.Models
{
    // Hoàng
    // Đối tượng chứa dữ liệu cho xử lý Đăng nhập
    public class LogOnModel
    {
        [Required(ErrorMessage = "Tên đăng nhập phải khác trống")]
        [Display(Name = "Tên đăng nhập: ")]
        [StringLength(20, MinimumLength = 3, ErrorMessage = "Tên đăng nhập phải có từ 3 đến 20 ký tự")]
        public string username { get; set; }

        [Required(ErrorMessage = "Mật khẩu phải khác trống")]
        [Display(Name = "Mật khẩu: ")]
        [StringLength(30, MinimumLength = 3, ErrorMessage = "Mật khẩu phải có từ 3 đến 30 ký tự")]
        [DataType(DataType.Password)]
        public string password { get; set; }

        [Display(Name = "Nhớ mật khẩu")]
        public bool rememberMe { get; set; }
    }


    // Hoàng
    // Đối tượng chứa dữ liệu cho xử lý đăng ký
    public class AccountRegisterModel
    {
        public static readonly string primaryGoogleCapchaKey = ConfigurationManager.AppSettings["primaryGoogleCapchaKey"];
        public static readonly string publicGoogleCapchaKey = ConfigurationManager.AppSettings["publicGoogleCapchaKey"];
        public static readonly int minAgeOfCustomer = int.Parse(ConfigurationManager.AppSettings["minAgeOfCustomer"]);
        public static readonly int maxAgeOfCustomer = int.Parse(ConfigurationManager.AppSettings["maxAgeOfCustomer"]);

        #region "Thuộc tính"
        [Display(Name = "Họ và tên:")]
        [RegularExpression(@"^[\D]*$", ErrorMessage = "Họ và tên không được chứa số")]
        [StringLength(200, ErrorMessage = "Họ và tên không được quá 200 ký tự!")]
        public string name { get; set; }

        [Display(Name = "Địa chỉ :")]
        [StringLength(500, ErrorMessage = "Địa chỉ không được quá 500 ký tự!")]
        [DataType(DataType.MultilineText)]
        public string address { get; set; }

        
        [Display(Name = "")]
        public int? dateOfBirth { get; set; }

        //[Display(Name = "")]
        public int monthOfBirth { get; set; }

        [Display(Name = "")]
        public int? yearOfBirth { get; set; }

        private DateTime? birthday;

        [Display(Name = "Điện thoại: ")]
        [StringLength(15, MinimumLength = 6, ErrorMessage = "Số điện thoại phải từ 6 đến 15 ký tự")]
        [DataType(DataType.PhoneNumber, ErrorMessage = "Số điện thoại phải là 1 dãy số hợp lệ.VD: 0986754322")]
        [RegularExpression(@"^ *\d{6,} *$", ErrorMessage = "Số điện thoại phải là 1 dãy số hợp lệ.VD: 0986754322")]
        public string phoneNumber { get; set; }

        [Required(ErrorMessage = "Tên đăng nhập phải khác trống")]
        [Display(Name = "Tên đăng nhập:")]
        [StringLength(20, MinimumLength = 3, ErrorMessage = "Tên đăng nhập phải có từ 3 đến 20 ký tự")]
        public string username { get; set; }

        [Required(ErrorMessage = "Mật khẩu phải khác trống")]
        [Display(Name = "Mật khẩu:")]
        [StringLength(30, MinimumLength = 3, ErrorMessage = "Mật khẩu phải có từ 3 đến 30 ký tự")]
        [DataType(DataType.Password)]
        public string password { get; set; }

        [Required(ErrorMessage = "Mật khẩu xác nhận phải khác trống")]
        [Display(Name = "Xác nhận mật khẩu:")]
        [DataType(DataType.Password)]
        [System.Web.Mvc.Compare("password", ErrorMessage = "Mật khẩu và mật khẩu xác nhận phải trùng nhau")]  // ???? 
        public string againPassword { get; set; }

        [Required(ErrorMessage = "Email phải khác trống")]
        [Display(Name = "Email:")]
        [StringLength(200, ErrorMessage = "Email không được quá 200 ký tự")]
        [DataType(DataType.EmailAddress)]
        [RegularExpression(@"^\w+(\.\w+)*@\w+(\.\w+)*\.[a-zA-Z]{2,4}$", ErrorMessage = "Email phải là địa chỉ email hợp lệ")]
        public string email { get; set; }

        #endregion

        #region "Các hàm kiểm tra và xử lý lưu xuống CSDL"
        // hàm kiểm tra lại để đảm bảo tổ hợp ngày sinh nhập vào từ 3 combobox là hợp lệ
        // thực hiện kiểm tra và tính ra giá trị ngày lưu vào birthday
        public bool chekAndCalculateBirthday()
        {
            try
            {
                if (yearOfBirth == null && monthOfBirth == 0 && dateOfBirth == null) // trường hợp người dùng ko nhập gì cả
                {
                    birthday = null; return true;
                }
                birthday = new DateTime((int)yearOfBirth, monthOfBirth, (int)dateOfBirth);
                int minAge = int.Parse(ConfigurationManager.AppSettings["minAgeOfCustomer"]);
                int maxAge = int.Parse(ConfigurationManager.AppSettings["maxAgeOfCustomer"]);
                int age = DateTime.Now.Year - (int)yearOfBirth;
                if (age < minAge || age > maxAge) return false;
            }
            catch
            {
                return false;
            }
            return true;
        }

        public string checkValid()
        {
            if (!chekAndCalculateBirthday())
                return "Ngày sinh không phải là ngày tháng năm hợp lệ !";
            if(AccountModels.UsernameExists(username.Trim()))
                return "Tên đăng nhập " + username + " đã được người khác đăng ký !";
            if (AccountModels.EmailExists(email.Trim()))
                return "Email " + email + " đã được đăng ký ở tài khoản khác !";

            return "";
        }

        // nếu ghi thất bại, hàm sẽ ném ngoại lệ
        public Account WriteToDatabase()
        {
            MobishopEntities content = new MobishopEntities();
            Account account = new Account();
            // đưa dữ liệu vào account mới tạo
            account.name = (this.name == null) ? "" : this.name.Trim();
            account.address = (this.address == null) ? "" : this.address.Trim();
            account.birthday = this.birthday;
            account.phoneNumber = (this.phoneNumber == null) ? "" : this.phoneNumber.Trim();
            account.email = this.email.Trim();
            account.username = this.username.Trim();
            account.password = AccountModels.GetMd5(this.password.Trim());
            account.creditCardNumber = null;
            account.role = 1;
            account.visible = true;
            account.cardCVV = null;
            account.cardMonthExpires = null;
            account.cardType = null;
            account.cardYearExpires = null;
            
            content.AccountList.AddObject(account);
            content.SaveChanges();

            return account;
        }
        #endregion
    }

    public class AccountModels
    {
        // hoàng
        // hàm đăng nhập người dùng với username và password chưa mã hóa
        // trả về null nếu thất bại
        public static Account Login(string username, string password)
        {
            password = GetMd5(password);
            return LoginWithMd5Password(username, password);
        }

        // hoàng
        // hàm đăng nhập người dùng với username và password đã mã hóa
        // trả về null nếu thất bại
        public static Account LoginWithMd5Password(string username, string password)
        {
            MobishopEntities content = new MobishopEntities();
            var query = from acc in content.AccountList
                        where acc.visible == true && acc.username == username && acc.password == password
                        select acc;
            if (query.Count() == 1) return query.First<Account>();
            return null;
        }

        //hoàng
        // trả về true nếu account được phép đăng nhập
        // hiện tại chỉ kiểm soát giá trị role
        public static bool IsAllowAccount(Account account)
        {
            return account!=null && (account.role == 1 || account.role == 2);
        }

        // hoàng
        // hàm mã hóa mật khẩu thành chuỗi md5
        public static string GetMd5(string chuoi)
        {
            chuoi = "af" + chuoi + "6q"; // nghịch tí =))

            string str_md5 = "";
            byte[] mang = System.Text.Encoding.UTF8.GetBytes(chuoi);

            MD5CryptoServiceProvider my_md5 = new MD5CryptoServiceProvider();
            mang = my_md5.ComputeHash(mang);

            foreach (byte b in mang)
            {
                str_md5 += b.ToString("X2");
            }

            return str_md5;
        }

        // hàm ghi cookies, nếu acc = null thì sẽ xóa cookies
        // phải truyền vào tham số là đối tượng Response
        public static void WriteCookies(Account account, HttpResponseBase Response)
        {
            string username, password;
            DateTime endDate;
            if (account == null)
            {
                username = ""; password = "";
                endDate = DateTime.Now.AddYears(-5); // hủy cookies
            }
            else
            {
                username = account.username; password = account.password;
                endDate = DateTime.Now.AddYears(1); // lưu cookies 1 năm
            }
            // ghi cookies
            HttpCookie cookie = new HttpCookie("username");
            cookie.Value = username;
            cookie.Expires = endDate;
            Response.Cookies.Add(cookie);

            cookie = new HttpCookie("password");
            cookie.Value = password;
            cookie.Expires = endDate;
            Response.Cookies.Add(cookie);
        }
        // hoàng
        public static bool UsernameExists(string username)
        {
            MobishopEntities content = new MobishopEntities();
            var query = from account in content.AccountList
                        where account.username == username
                        select account;
            return query.Count() > 0;
        }
        // hoàng
        public static bool EmailExists(string email)
        {
            MobishopEntities content = new MobishopEntities();
            return content.AccountList.Where(acc => acc.email == email).Count()>0;
        }
        // hoàng
        public static string EncodeCreditCardNumber(string number)
        {
            if (number == null) return "";
            if (number.Length <= 4) return number;
            string str = "";
            for (int i = 4; i < number.Length; i++) str += "X";
            return number.Substring(0, 4) + str;
        }
        // hoàng
        public static string EncodeCreditCardCVV(string cvv)
        {
            if (cvv == null) return "";
            string str = "";
            for (int i = 0; i < cvv.Length; i++) str += "X";
            return str;
        }
    }

    public class FindAccountData
    {
        public FindAccountData()
        {
        }

        [Display(Name = "Họ tên:")]
        public string name { get; set; }

        [Display(Name = "Tên đăng nhập:")]
        public string username { get; set; }

        [Display(Name = "Địa chỉ:")]
        public string address { get; set; }

        [Display(Name = "Điện thoại:")]
        [RegularExpression(@"^\d*$", ErrorMessage = "Số điện thoại phải là 1 dãy số")]
        public string phoneNumber { get; set; }

        [Display(Name = "Email:")]
        public string email { get; set; }

        [Display(Name = "Vai trò:")]
        public byte? role { get; set; }

        [Display(Name = "Tình trạng:")]
        public bool? visible { get; set; }

        public IQueryable<Account> Find(MobishopEntities db)
        {
            var list = from s in db.AccountList
                       select s;
            // tiến hành lọc theo các tiêu chí tìm kiếm:
            if (name != null && name.Length > 0)
                list = list.Where(s => s.name.Contains(name));
            if (username != null && username.Length > 0)
                list = list.Where(s => s.username.Contains(username));
            if (address != null && address.Length > 0)
                list = list.Where(s => s.address.Contains(address));
            if (phoneNumber != null && phoneNumber.Length > 0)
                list = list.Where(s => s.phoneNumber.Contains(phoneNumber));
            if (email != null && email.Length > 0)
                list = list.Where(s => s.email.Contains(email));

            if (role != null)
                list = list.Where(s => s.role == role);

            if (visible != null)
            {
                if ((bool)visible)
                    list = list.Where(s => s.visible == true);
                else
                    list = list.Where(s => s.visible == false || s.visible == null);
            }

            return list;
        }
    }
}